home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / ccm / Pages.py < prev    next >
Encoding:
Python Source  |  2009-03-04  |  51.6 KB  |  1,406 lines

  1. #!/usr/bin/env python
  2. # -*- coding: UTF-8 -*-
  3.  
  4. # This program is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU General Public License
  6. # as published by the Free Software Foundation; either version 2
  7. # of the License, or (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful, 
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17. #
  18. # Authors: Quinn Storm (quinn@beryl-project.org)
  19. #          Patrick Niklaus (marex@opencompositing.org)
  20. #          Guillaume Seguin (guillaume@segu.in)
  21. #          Christopher Williams (christopherw@verizon.net)
  22. # Copyright (C) 2007 Quinn Storm
  23.  
  24. import pygtk
  25. import gtk
  26. import gobject
  27. import gtk.gdk
  28.  
  29. import compizconfig
  30. ccs = compizconfig
  31.  
  32. from ccm.Constants import *
  33. from ccm.Settings import *
  34. from ccm.Conflicts import *
  35. from ccm.Utils import *
  36. from ccm.Widgets import *
  37.  
  38. import locale
  39. import gettext
  40. locale.setlocale(locale.LC_ALL, "")
  41. gettext.bindtextdomain("ccsm", DataDir + "/locale")
  42. gettext.textdomain("ccsm")
  43. _ = gettext.gettext
  44.  
  45. CurrentUpdater = None
  46.  
  47. # Generic Page
  48. #
  49. class GenericPage(gobject.GObject):
  50.     __gsignals__    = {"go-back" : (gobject.SIGNAL_RUN_FIRST,
  51.                                     gobject.TYPE_NONE,
  52.                                     [])}
  53.  
  54.     LeftWidget = None
  55.     RightWidget = None
  56.  
  57.     def __init__(self):
  58.         gobject.GObject.__init__(self)
  59.  
  60.     def GoBack(self, widget):
  61.         self.emit('go-back')
  62.  
  63. # Plugin Page
  64. #
  65. class PluginPage(GenericPage):
  66.  
  67.     def __init__(self, plugin):
  68.         GenericPage.__init__(self)
  69.         self.Plugin = plugin
  70.         self.LeftWidget = gtk.VBox(False, 10)
  71.         self.LeftWidget.set_border_width(10)
  72.  
  73.         pluginLabel = Label()
  74.         pluginLabel.set_markup(HeaderMarkup % (plugin.ShortDesc))
  75.         pluginLabel.connect("style-set", self.HeaderStyleSet)
  76.         pluginImg = Image(plugin.Name, ImagePlugin, 64)
  77.         filterLabel = Label()
  78.         filterLabel.set_markup(HeaderMarkup % (_("Filter")))
  79.         filterLabel.connect("style-set", self.HeaderStyleSet)
  80.         if has_sexy:
  81.             self.FilterEntry = sexy.IconEntry()
  82.             self.FilterEntry.add_clear_button()
  83.         else:
  84.             self.FilterEntry = gtk.Entry()
  85.         self.FilterEntry.connect("changed", self.FilterChanged)
  86.  
  87.         self.LeftWidget.pack_start(pluginImg, False, False)
  88.         self.LeftWidget.pack_start(filterLabel, False, False)
  89.         self.LeftWidget.pack_start(self.FilterEntry, False, False)
  90.         self.LeftWidget.pack_start(pluginLabel, False, False)
  91.         infoLabelCont = gtk.HBox()
  92.         infoLabelCont.set_border_width(10)
  93.         self.LeftWidget.pack_start(infoLabelCont, False, False)
  94.         infoLabel = Label(plugin.LongDesc, 180)
  95.         infoLabelCont.pack_start(infoLabel, True, True)
  96.  
  97.         self.NotFoundBox = None
  98.         
  99.         if plugin.Name != 'core':
  100.             self.FilterEntry.set_tooltip_text(_("Search %s Plugin Options") % plugin.ShortDesc)
  101.             enableLabel = Label()
  102.             enableLabel.set_markup(HeaderMarkup % (_("Use This Plugin")))
  103.             enableLabel.connect("style-set", self.HeaderStyleSet)
  104.             self.LeftWidget.pack_start(enableLabel, False, False)
  105.             enableCheckCont = gtk.HBox()
  106.             enableCheckCont.set_border_width(10)
  107.             self.LeftWidget.pack_start(enableCheckCont, False, False)
  108.             enableCheck = gtk.CheckButton()
  109.             enableCheck.add(Label(_("Enable %s") % plugin.ShortDesc, 120))
  110.             enableCheck.set_tooltip_text(plugin.LongDesc)
  111.             enableCheck.set_active(plugin.Enabled)
  112.             enableCheck.set_sensitive(plugin.Context.AutoSort)
  113.             enableCheckCont.pack_start(enableCheck, True, True)
  114.             enableCheck.connect('toggled', self.EnablePlugin)
  115.         else:
  116.             self.FilterEntry.set_tooltip_text(_("Search Compiz Core Options"))
  117.         
  118.         backButton = gtk.Button(gtk.STOCK_GO_BACK)
  119.         backButton.set_use_stock(True)
  120.         self.LeftWidget.pack_end(backButton, False, False)
  121.         backButton.connect('clicked', self.GoBack)
  122.         self.RightWidget = gtk.Notebook()
  123.         self.RightWidget.set_scrollable(True)
  124.         self.Pages = []
  125.  
  126.         sortedGroups = sorted(plugin.Groups.items(), key=GroupIndexKeyFunc)
  127.         for (name, (groupIndex, group)) in sortedGroups:
  128.             name = name or _("General")
  129.             groupPage = GroupPage(name, group)
  130.             groupPage.Wrap()
  131.             if not groupPage.Empty:
  132.                 self.RightWidget.append_page(groupPage.Scroll, gtk.Label(name))
  133.                 self.Pages.append(groupPage)
  134.         
  135.         self.RightWidget.connect('size-allocate', self.ResetFocus)
  136.  
  137.         self.Block = 0
  138.  
  139.     StyleBlock = 0
  140.  
  141.     def HeaderStyleSet(self, widget, previous):
  142.         if self.StyleBlock > 0:
  143.             return
  144.         self.StyleBlock += 1
  145.         for state in (gtk.STATE_NORMAL, gtk.STATE_PRELIGHT, gtk.STATE_ACTIVE):
  146.             widget.modify_fg(state, widget.style.bg[gtk.STATE_SELECTED])
  147.         self.StyleBlock -= 1
  148.  
  149.     def ResetFocus(self, widget, data):
  150.         pos = self.FilterEntry.get_position() 
  151.         self.FilterEntry.grab_focus()
  152.         self.FilterEntry.set_position(pos)
  153.  
  154.     def GetPageSpot(self, new):
  155.         vpos = 0 #visible position
  156.         for page in self.Pages:
  157.             if page is new:
  158.                 break
  159.             if page.Visible:
  160.                 vpos += 1
  161.         return vpos
  162.  
  163.     def ShowFilterError(self, text):
  164.  
  165.         if self.NotFoundBox is None:
  166.             self.NotFoundBox = NotFoundBox(text)
  167.             self.RightWidget.append_page(self.NotFoundBox, gtk.Label(_("Error")))
  168.         else:
  169.             self.NotFoundBox.update(text)
  170.  
  171.     def HideFilterError(self):
  172.         if self.NotFoundBox is None:
  173.             return
  174.         num = self.RightWidget.page_num(self.NotFoundBox)
  175.         if num >= 0:
  176.             self.RightWidget.remove_page(num)
  177.         self.NotFoundBox.destroy()
  178.         self.NotFoundBox = None
  179.  
  180.         self.RightWidget.set_current_page(0)
  181.  
  182.     def FilterChanged(self, widget):
  183.         text = widget.get_text().lower()
  184.         if text == "":
  185.             text = None
  186.  
  187.         empty = True
  188.         for page in self.Pages:
  189.             num = self.RightWidget.page_num(page.Scroll)
  190.             if page.Filter(text):
  191.                 empty = False
  192.                 if num < 0:
  193.                     self.RightWidget.insert_page(page.Scroll, gtk.Label(page.Name), self.GetPageSpot(page))
  194.             else:
  195.                 if num >= 0:
  196.                     self.RightWidget.remove_page(num)
  197.  
  198.         if empty:
  199.             self.ShowFilterError(text)
  200.         else:
  201.             self.HideFilterError()
  202.  
  203.         self.RightWidget.show_all()
  204.  
  205.         # This seems to be necessary to ensure all gaps from hidden settings are removed on all tabs
  206.         for page in self.Pages:
  207.             page.Scroll.queue_resize_no_redraw()
  208.  
  209.  
  210.     def EnablePlugin(self, widget):
  211.         if self.Block > 0:
  212.             return
  213.         self.Block += 1
  214.         # attempt to resolve conflicts...
  215.         conflicts = self.Plugin.Enabled and self.Plugin.DisableConflicts or self.Plugin.EnableConflicts
  216.         conflict = PluginConflict(self.Plugin, conflicts)
  217.         if conflict.Resolve():
  218.             self.Plugin.Enabled = widget.get_active()
  219.         else:
  220.             widget.set_active(self.Plugin.Enabled)
  221.         self.Plugin.Context.Write()
  222.         self.Block -= 1
  223.         GlobalUpdater.UpdatePlugins()
  224.  
  225.     # Checks if any edit dialog is open, and if so, makes sure a refresh
  226.     # happens when it closes.
  227.     def CheckDialogs(self, basePlugin, main):
  228.         for groupPage in self.Pages:
  229.             if isinstance(groupPage, GroupPage):
  230.                 for sga in groupPage.subGroupAreas:
  231.                     for setting in sga.MySettings:
  232.                         if isinstance(setting, BaseListSetting) and \
  233.                         setting.EditDialog and setting.EditDialogOpen:
  234.                             setting.PageToBeRefreshed = (self, basePlugin, main)
  235.                             return False
  236.         return True
  237.  
  238.     def RefreshPage(self, basePlugin, main):
  239.         curPage = self.RightWidget.get_current_page ()
  240.         main.BackToMain (None)
  241.         main.MainPage.ShowPlugin (None, basePlugin)
  242.         main.CurrentPage.RightWidget.set_current_page (curPage)
  243.  
  244. # Filter Page
  245. #
  246. class FilterPage(GenericPage):
  247.     def __init__(self, context):
  248.         GenericPage.__init__(self)
  249.         self.Context = context
  250.         self.LeftWidget = gtk.VBox(False, 10)
  251.         self.LeftWidget.set_border_width(10)
  252.         self.RightWidget = gtk.Notebook()
  253.         self.RightChild = gtk.VBox()
  254.  
  255.         # Image + Label
  256.         filterLabel = Label()
  257.         filterLabel.set_markup(HeaderMarkup % (_("Filter")))
  258.         filterLabel.connect("style-set", self.HeaderStyleSet)
  259.         filterImg = Image("search", ImageCategory, 64)
  260.         self.LeftWidget.pack_start(filterImg, False, False)
  261.         self.LeftWidget.pack_start(filterLabel, False, False)
  262.         
  263.         # Entry
  264.         if has_sexy:
  265.             self.FilterEntry = sexy.IconEntry()
  266.             self.FilterEntry.add_clear_button()
  267.             keyboardImage = Image("input-keyboard", ImageThemed, 16)
  268.             self.FilterEntry.set_icon(sexy.ICON_ENTRY_PRIMARY, keyboardImage)
  269.             self.FilterEntry.set_icon_highlight(sexy.ICON_ENTRY_PRIMARY, True)
  270.             self.FilterEntry.connect('icon-pressed', self.GrabKey)
  271.         else:
  272.             self.FilterEntry = gtk.Entry()
  273.  
  274.         self.FilterEntry.set_tooltip_text(_("Enter a filter.\nClick the keyboard image to grab a key for which to search."))
  275.         self.FilterEntry.connect("changed", self.FilterChanged)
  276.         self.LeftWidget.pack_start(self.FilterEntry, False, False)
  277.  
  278.         # Search in...
  279.         filterSearchLabel = Label()
  280.         filterSearchLabel.set_markup(HeaderMarkup % (_("Search in...")))
  281.         filterSearchLabel.connect("style-set", self.HeaderStyleSet)
  282.         self.LeftWidget.pack_start(filterSearchLabel, False, False)
  283.  
  284.         # Options
  285.         self.FilterNameCheck = check = gtk.CheckButton(_("Short description and name"))
  286.         check.set_active(True)
  287.         check.connect("toggled", self.LevelChanged, FilterName)
  288.         self.LeftWidget.pack_start(check, False, False)
  289.  
  290.         self.FilterLongDescCheck = check = gtk.CheckButton(_("Long description"))
  291.         check.set_active(True)
  292.         check.connect("toggled", self.LevelChanged, FilterLongDesc)
  293.         self.LeftWidget.pack_start(check, False, False)
  294.         
  295.         self.FilterValueCheck = check = gtk.CheckButton(_("Settings value"))
  296.         check.set_active(False)
  297.         check.connect("toggled", self.LevelChanged, FilterValue)
  298.         self.LeftWidget.pack_start(check, False, False)
  299.  
  300.         # Back Button
  301.         self.BackButton = gtk.Button(gtk.STOCK_GO_BACK)
  302.         self.BackButton.set_use_stock(True)
  303.         self.BackButton.connect('clicked', self.GoBack)
  304.         self.LeftWidget.pack_end(self.BackButton, False, False)
  305.  
  306.         self.NotFoundBox = None
  307.  
  308.         # Selector
  309.         self.CurrentPlugin = None
  310.         self.CurrentGroup = None
  311.         self.CurrentSubGroup = None
  312.  
  313.         self.PackedPlugins = ()
  314.         self.PackedGroups = ()
  315.         self.PackedSubGroups = ()
  316.  
  317.         self.SelectorButtons = SelectorButtons()
  318.         self.PluginBox = PluginView(context.Plugins)
  319.         self.PluginBox.SelectionHandler = self.PluginChanged
  320.         self.GroupBox = GroupView(_("Group"))
  321.         self.GroupBox.SelectionHandler = self.GroupChanged
  322.         self.SubGroupBox = GroupView(_("Subgroup"))
  323.         self.SubGroupBox.SelectionHandler = self.SubGroupChanged
  324.  
  325.         self.PluginBox.set_size_request(250, 180)
  326.         self.GroupBox.set_size_request(220, 180)
  327.         self.SubGroupBox.set_size_request(220, 180)
  328.  
  329.         self.SelectorButtons.set_size_request(-1, 50)
  330.  
  331.         self.SelectorBoxes = gtk.HBox()
  332.         self.SelectorBoxes.set_border_width(5)
  333.         self.SelectorBoxes.set_spacing(5)
  334.  
  335.         scroll = gtk.ScrolledWindow()
  336.         scroll.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC
  337.         scroll.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
  338.         scroll.add(self.PluginBox)
  339.         self.SelectorBoxes.pack_start(scroll, False, False)
  340.         scroll = gtk.ScrolledWindow()
  341.         scroll.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC
  342.         scroll.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
  343.         scroll.add(self.GroupBox)
  344.         self.SelectorBoxes.pack_start(scroll, False, False)
  345.         scroll = gtk.ScrolledWindow()
  346.         scroll.add(self.SubGroupBox)
  347.         scroll.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC
  348.         scroll.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
  349.         self.SelectorBoxes.pack_start(scroll, False, False)
  350.         self.RightChild.pack_start(self.SelectorButtons, False, False)
  351.         self.RightChild.pack_start(self.SelectorBoxes, False, False)
  352.         self.SettingsArea = gtk.ScrolledWindow()
  353.         ebox = gtk.EventBox()
  354.         self.SettingsBox = gtk.VBox()
  355.         ebox.add(self.SettingsBox)
  356.         self.SettingsBox.set_border_width(5)
  357.         self.SettingsArea.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC
  358.         self.SettingsArea.props.vscrollbar_policy = gtk.POLICY_ALWAYS
  359.         self.SettingsArea.set_border_width(5)
  360.         self.SettingsArea.add_with_viewport(ebox)
  361.         self.RightChild.pack_start(self.SettingsArea, True, True)
  362.  
  363.         GlobalUpdater.Block += 1
  364.  
  365.         # Notebook
  366.         self.NotebookLabel = gtk.Label(_("Settings"))
  367.         self.NotebookChild = gtk.EventBox()
  368.         self.NotebookChild.add(self.RightChild)
  369.         self.RightWidget.append_page(self.NotebookChild, self.NotebookLabel)
  370.  
  371.         box = gtk.VBox()
  372.         box.set_border_width(5)
  373.         progress = Popup(child=box)
  374.         progress.connect("delete-event", lambda *a: True)
  375.         progress.set_title(_("Loading Advanced Search"))
  376.         bar = gtk.ProgressBar()
  377.         box.pack_start(bar, False, False)
  378.  
  379.         label = gtk.Label()
  380.         box.pack_start(label, False, False)
  381.  
  382.         progress.set_size_request(300, -1)
  383.  
  384.         progress.show_all()
  385.  
  386.         self.GroupPages = {}
  387.  
  388.         length = len(context.Plugins)
  389.  
  390.         for index, (plugin, Plugin) in enumerate(context.Plugins.items()):
  391.  
  392.             bar.set_fraction((index+1)/float(length))
  393.             label.set_markup("<i>%s</i>" %protect_pango_markup(Plugin.ShortDesc))
  394.             gtk_process_events()
  395.  
  396.             groups = []
  397.             sortedGroups = sorted(Plugin.Groups.items(), key=GroupIndexKeyFunc)
  398.             for (name, (groupIndex, group)) in sortedGroups:
  399.                 groups.append((name, GroupPage(name or _('General'), group)))
  400.             self.GroupPages[plugin] = groups
  401.  
  402.         self.Level = FilterName | FilterLongDesc
  403.  
  404.         self.FilterChanged()
  405.  
  406.         progress.destroy()
  407.  
  408.         gtk_process_events()
  409.  
  410.         GlobalUpdater.Block -= 1
  411.  
  412.     StyleBlock = 0
  413.  
  414.     def HeaderStyleSet(self, widget, previous):
  415.         if self.StyleBlock > 0:
  416.             return
  417.         self.StyleBlock += 1
  418.         for state in (gtk.STATE_NORMAL, gtk.STATE_PRELIGHT, gtk.STATE_ACTIVE):
  419.             widget.modify_fg(state, widget.style.bg[gtk.STATE_SELECTED])
  420.         self.StyleBlock -= 1
  421.  
  422.     def Filter(self, text, level=FilterAll):
  423.         text = text.lower()
  424.         for plugin, groups in self.GroupPages.items():
  425.             results = dict((n, sg) for (n, sg) in groups if sg.Filter(text, level=level))
  426.             if results:
  427.                 yield plugin, results
  428.  
  429.     def GotKey(self, widget, key, mods):
  430.         new = gtk.accelerator_name (key, mods)
  431.         for mod in KeyModifier:
  432.             if "%s_L" % mod in new:
  433.                 new = new.replace ("%s_L" % mod, "<%s>" % mod)
  434.             if "%s_R" % mod in new:
  435.                 new = new.replace ("%s_R" % mod, "<%s>" % mod)
  436.  
  437.         widget.destroy()
  438.         self.FilterValueCheck.set_active(True)
  439.         self.FilterEntry.set_text(new)
  440.  
  441.     def GrabKey(self, widget, pos, button):
  442.         if not has_sexy or pos != sexy.ICON_ENTRY_PRIMARY:
  443.             return
  444.         grabber = KeyGrabber(label = _("Grab key combination"))
  445.         self.LeftWidget.pack_start(grabber, False, False)
  446.         grabber.hide()
  447.         grabber.set_no_show_all(True)
  448.         grabber.connect('changed', self.GotKey)
  449.         grabber.begin_key_grab(None)
  450.  
  451.     def ShowFilterError(self, text):
  452.  
  453.         if self.NotFoundBox is None:
  454.             self.NotFoundBox = NotFoundBox(text)
  455.             self.NotebookChild.remove(self.RightChild)
  456.             self.NotebookChild.add(self.NotFoundBox)
  457.             self.NotebookLabel.set_text(_("Error"))
  458.             self.NotebookChild.show_all()
  459.         else:
  460.             self.NotFoundBox.update(text)
  461.  
  462.     def HideFilterError(self):
  463.         if self.NotFoundBox is None:
  464.             return
  465.         num = self.RightWidget.page_num(self.NotFoundBox)
  466.         if num >= 0:
  467.             self.RightWidget.remove_page(num)
  468.  
  469.         self.NotebookChild.remove(self.NotFoundBox)
  470.         self.NotebookChild.add(self.RightChild)
  471.  
  472.         self.NotFoundBox.destroy()
  473.         self.NotFoundBox = None
  474.  
  475.         self.NotebookLabel.set_text(_("Settings"))
  476.  
  477.         self.NotebookChild.show_all()
  478.  
  479.     def UpdatePluginBox(self):
  480.         self.PluginBox.Filter(self.Results)
  481.     
  482.         self.UpdateGroupBox()
  483.  
  484.     def UpdateGroupBox(self):
  485.         if self.CurrentPlugin is None:
  486.             self.GroupBox.Update(())
  487.         else:
  488.             self.GroupBox.Update(self.Results[self.CurrentPlugin.Name])
  489.         self.UpdateSubGroupBox()
  490.  
  491.     def UpdateSubGroupBox(self):
  492.         if self.CurrentPlugin is not None and self.CurrentGroup in self.Results[self.CurrentPlugin.Name]:
  493.             grouppage = self.Results[self.CurrentPlugin.Name][self.CurrentGroup]
  494.             self.SubGroupBox.Update(sga.Name for sga in grouppage.VisibleAreas)
  495.         else:
  496.             self.SubGroupBox.Update(())
  497.  
  498.     def UpdateSelectorButtons(self):
  499.         self.SelectorButtons.clear_buttons()
  500.         if self.CurrentPlugin is not None:
  501.             self.SelectorButtons.add_button(self.CurrentPlugin.ShortDesc, self.PluginChanged)
  502.             if self.CurrentGroup is not None:
  503.                 self.SelectorButtons.add_button(self.CurrentGroup or _("General"), self.GroupChanged)
  504.                 if self.CurrentSubGroup is not None:
  505.                     self.SelectorButtons.add_button(self.CurrentSubGroup or _("General"), self.SubGroupChanged)
  506.  
  507.     def PluginChanged(self, plugin=None, selector=False):
  508.         if not selector:
  509.             self.CurrentPlugin = plugin
  510.         self.CurrentGroup = None
  511.         self.CurrentSubGroup = None
  512.  
  513.         self.UpdateSelectorButtons()
  514.         if not selector:
  515.             self.UpdateGroupBox()
  516.         else:
  517.             self.GroupBox.get_selection().unselect_all()
  518.             self.UpdateSubGroupBox()
  519.  
  520.         if self.CurrentPlugin is not None:
  521.             self.PackSettingsBox(plugins=[self.CurrentPlugin])
  522.         else:
  523.             self.PackSettingsBox()
  524.  
  525.         self.RightChild.show_all()
  526.  
  527.     def GroupChanged(self, group=None, selector=False):
  528.  
  529.         if group == 'All':
  530.             self.PluginChanged(selector=True)
  531.             return
  532.  
  533.         if not selector:
  534.             self.CurrentGroup = group
  535.         self.CurrentSubGroup = None
  536.  
  537.         self.UpdateSelectorButtons()
  538.  
  539.         if not selector:
  540.             self.UpdateSubGroupBox()
  541.         else:
  542.             self.SubGroupBox.get_selection().unselect_all()
  543.  
  544.         if self.CurrentGroup is not None:
  545.             page = self.Results[self.CurrentPlugin.Name][self.CurrentGroup]
  546.             self.PackSettingsBox(groups=[page])
  547.         else:
  548.             self.PackSettingsBox()
  549.  
  550.         self.RightChild.show_all()
  551.  
  552.     def SubGroupChanged(self, subGroup=None, selector=False):
  553.  
  554.         if subGroup == 'All':
  555.             self.GroupChanged(selector=True)
  556.             return
  557.  
  558.         if not selector:
  559.             self.CurrentSubGroup = subGroup
  560.  
  561.         self.UpdateSelectorButtons()
  562.  
  563.         if self.CurrentSubGroup is not None:
  564.             sgas = self.Results[self.CurrentPlugin.Name][self.CurrentGroup].VisibleAreas
  565.             sga = [sga for sga in sgas if sga.Name == self.CurrentSubGroup]
  566.             self.PackSettingsBox(subgroups=sga)
  567.         else:
  568.             self.PackSettingsBox()
  569.         self.RightChild.show_all()
  570.  
  571.     def LevelChanged(self, widget, level):
  572.  
  573.         if widget.get_active():
  574.             if level & self.Level:
  575.                 return
  576.             self.Level |= level
  577.         else:
  578.             if not level & self.Level:
  579.                 return
  580.             self.Level &= ~level
  581.  
  582.         self.FilterChanged()
  583.  
  584.     def PackSettingsBox(self, plugins=None, groups=None, subgroups=None):
  585.  
  586.         for pluginbox in self.PackedPlugins:
  587.             for child in pluginbox.get_children():
  588.                 pluginbox.remove(child)
  589.             pluginbox.destroy()
  590.         self.PackedPlugins = ()
  591.         for group in self.PackedGroups:
  592.             if group.Widget.get_parent():
  593.                 group.Widget.get_parent().remove(group.Widget)
  594.         self.PackedGroups = ()
  595.         for subgroup in self.PackedSubGroups:
  596.             if subgroup.Widget.get_parent():
  597.                 subgroup.Widget.get_parent().remove(subgroup.Widget)
  598.             subgroup.Widget.destroy()
  599.         self.PackedSubGroups = ()
  600.  
  601.         if plugins is not None:
  602.             self.PackedPlugins = []
  603.             self.PackedGroups = []
  604.             for plugin in plugins:
  605.                 box = gtk.VBox()
  606.                 for (pageName, page) in self.GroupPages[plugin.Name]:
  607.                     box.pack_start(page.Label, False, False)
  608.                     box.pack_start(page.Widget, False, False)
  609.  
  610.                     self.PackedGroups.append(page)
  611.                 self.SettingsBox.pack_start(box, False, False)
  612.                 self.PackedPlugins.append(box)
  613.  
  614.         if groups is not None:
  615.             self.PackedGroups = []
  616.             for page in groups:
  617.                 self.SettingsBox.pack_start(page.Widget, False, False)
  618.                 self.PackedGroups.append(page)
  619.  
  620.         if subgroups is not None:
  621.             self.PackedSubGroups = []
  622.             for area in subgroups:
  623.                 sga = SubGroupArea('', area.SubGroup)
  624.                 sga.Filter(self.FilterEntry.get_text().lower())
  625.                 self.SettingsBox.pack_start(sga.Widget, False, False)     
  626.                 self.PackedSubGroups.append(sga)
  627.  
  628.         self.SettingsBox.show_all()
  629.  
  630.     def FilterChanged(self, widget=None):
  631.  
  632.         self.Results = dict(self.Filter(self.FilterEntry.get_text(), level=self.Level))
  633.  
  634.         self.PluginBox.Filter(self.Results)
  635.         self.UpdateGroupBox()
  636.  
  637.         self.UpdateSelectorButtons()
  638.  
  639.         for sga in self.PackedSubGroups:
  640.             sga.Filter(self.FilterEntry.get_text().lower())
  641.  
  642.         self.SettingsBox.queue_resize_no_redraw()
  643.  
  644.         self.RightWidget.show_all()
  645.  
  646.         if not self.Results:
  647.             self.ShowFilterError(self.FilterEntry.get_text())
  648.         elif self.NotFoundBox:
  649.             self.HideFilterError()
  650.  
  651.     def GoBack(self, widget):
  652.         for groups in self.GroupPages.values():
  653.             for (pageName, page) in groups:
  654.                 page.SetContainer.destroy()
  655.         self.GroupPages = None
  656.  
  657.         self.emit('go-back')
  658.  
  659. # Profile and Backend Page
  660. #
  661. class ProfileBackendPage(object):
  662.     def __init__(self, context):
  663.         self.Context = context
  664.         rightChild = gtk.VBox()
  665.         rightChild.set_border_width(10)
  666.  
  667.         # Profiles
  668.         profileBox = gtk.HBox()
  669.         profileBox.set_spacing(5)
  670.         profileAdd = gtk.Button()
  671.         profileAdd.set_tooltip_text(_("Add a New Profile"))
  672.         profileAdd.set_image(gtk.image_new_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON))
  673.         self.ProfileRemoveButton = profileRemove = gtk.Button()
  674.         profileRemove.set_tooltip_text(_("Remove This Profile"))
  675.         profileRemove.set_image(gtk.image_new_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON))
  676.         self.ProfileComboBox = gtk.combo_box_new_text()
  677.         self.ProfileComboBox.set_sensitive(self.Context.CurrentBackend.ProfileSupport)
  678.         self.ProfileComboBox.append_text(_("Default"))
  679.         for profile in self.Context.Profiles.values():
  680.             self.ProfileComboBox.append_text(profile.Name)
  681.         self.ProfileHandler = self.ProfileComboBox.connect("changed",
  682.             self.ProfileChangedAddTimeout)
  683.         name = self.Context.CurrentProfile.Name
  684.         if name in self.Context.Profiles: 
  685.             index = self.Context.Profiles.values().index(self.Context.Profiles[name])
  686.             self.ProfileComboBox.set_active(index+1)
  687.         else:
  688.             self.ProfileComboBox.set_active(0) 
  689.         profileAdd.connect("clicked", self.AddProfile)
  690.         profileRemove.connect("clicked", self.RemoveProfile)
  691.         profileBox.pack_start(self.ProfileComboBox, True, True)
  692.         profileBox.pack_start(profileAdd, False, False)
  693.         profileBox.pack_start(profileRemove, False, False)
  694.         profileLabel = Label()
  695.         profileLabel.set_markup(HeaderMarkup % (_("Profile")))
  696.         profileLabel.connect("style-set", self.HeaderStyleSet)
  697.         self.ProfileImportExportBox = gtk.HBox()
  698.         self.ProfileImportExportBox.set_spacing(5)
  699.         profileImportButton = gtk.Button(_("Import"))
  700.         profileImportButton.set_tooltip_text(_("Import a CompizConfig Profile"))
  701.         profileImportAsButton = gtk.Button(_("Import as..."))
  702.         profileImportAsButton.set_tooltip_text(_("Import a CompizConfig Profile as a new profile"))
  703.         profileExportButton = gtk.Button(_("Export"))
  704.         profileExportButton.set_tooltip_text(_("Export your CompizConfig Profile"))
  705.         profileResetButton = gtk.Button(_("Reset to defaults"))
  706.         profileResetButton.set_tooltip_text(_("Reset your CompizConfig Profile to the global defaults"))
  707.         profileResetButton.set_image(gtk.image_new_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_BUTTON))
  708.         profileImportButton.set_image(gtk.image_new_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON))
  709.         profileImportAsButton.set_image(gtk.image_new_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON))
  710.         profileExportButton.set_image(gtk.image_new_from_stock(gtk.STOCK_SAVE, gtk.ICON_SIZE_BUTTON))
  711.         profileImportButton.connect("clicked", self.ImportProfile)
  712.         profileImportAsButton.connect("clicked", self.ImportProfileAs)
  713.         profileExportButton.connect("clicked", self.ExportProfile)
  714.         profileResetButton.connect("clicked", self.ResetProfile)
  715.         self.ProfileImportExportBox.pack_start(profileImportButton, False, False)
  716.         self.ProfileImportExportBox.pack_start(profileImportAsButton, False, False)
  717.         self.ProfileImportExportBox.pack_start(profileExportButton, False, False)
  718.         self.ProfileImportExportBox.pack_start(profileResetButton, False, False)
  719.         rightChild.pack_start(profileLabel, False, False, 5)
  720.         rightChild.pack_start(profileBox, False, False, 5)
  721.         rightChild.pack_start(self.ProfileImportExportBox, False, False, 5)
  722.  
  723.         # Backends
  724.         backendBox = gtk.combo_box_new_text()
  725.         for backend in self.Context.Backends.values():
  726.             backendBox.append_text(backend.ShortDesc)
  727.         name = self.Context.CurrentBackend.Name
  728.         index = self.Context.Backends.values().index(self.Context.Backends[name])
  729.         backendBox.set_active(index)
  730.         backendBox.connect("changed", self.BackendChangedAddTimeout)
  731.         backendLabel = Label()
  732.         backendLabel.set_markup(HeaderMarkup % (_("Backend")))
  733.         backendLabel.connect("style-set", self.HeaderStyleSet)
  734.         rightChild.pack_start(backendLabel, False, False, 5)
  735.         rightChild.pack_start(backendBox, False, False, 5)
  736.  
  737.         # Integration
  738.         integrationLabel = Label()
  739.         integrationLabel.set_markup(HeaderMarkup % (_("Integration")))
  740.         integrationLabel.connect("style-set", self.HeaderStyleSet)
  741.         self.IntegrationButton = gtk.CheckButton(_("Enable integration into the desktop environment"))
  742.         self.IntegrationButton.set_active(self.Context.Integration)
  743.         self.IntegrationButton.set_sensitive(self.Context.CurrentBackend.IntegrationSupport)
  744.         self.IntegrationButton.connect("toggled", self.IntegrationChanged)
  745.         rightChild.pack_start(integrationLabel, False, False, 5)
  746.         rightChild.pack_start(self.IntegrationButton, False, False, 5)
  747.  
  748.         self.Widget = rightChild
  749.     
  750.     StyleBlock = 0
  751.  
  752.     def HeaderStyleSet(self, widget, previous):
  753.         if self.StyleBlock > 0:
  754.             return
  755.         self.StyleBlock += 1
  756.         for state in (gtk.STATE_NORMAL, gtk.STATE_PRELIGHT, gtk.STATE_ACTIVE):
  757.             widget.modify_fg(state, widget.style.bg[gtk.STATE_SELECTED])
  758.         self.StyleBlock -= 1
  759.  
  760.     def UpdateProfiles (self, current=_("Default")):
  761.  
  762.         self.ProfileComboBox.handler_block (self.ProfileHandler)
  763.  
  764.         self.Context.Read ()
  765.         self.Context.UpdateProfiles ()
  766.  
  767.         self.ProfileComboBox.get_model ().clear ()
  768.         set = False
  769.         for index, profile in enumerate ([_("Default")] + list (self.Context.Profiles)):
  770.             self.ProfileComboBox.append_text (profile)
  771.             if profile == current and not set:
  772.                 self.ProfileComboBox.set_active (index)
  773.                 set = True
  774.         self.ProfileRemoveButton.set_sensitive (self.ProfileComboBox.get_active() != 0)
  775.  
  776.         self.ProfileComboBox.handler_unblock (self.ProfileHandler)
  777.  
  778.         GlobalUpdater.UpdatePlugins()
  779.  
  780.     def IntegrationChanged(self, widget):
  781.         value = widget.get_active()
  782.         self.Context.Integration = value
  783.  
  784.     def ProfileChanged(self, widget):
  785.         name = widget.get_active_text()
  786.         if name == _("Default"):
  787.             self.Context.ResetProfile()
  788.         elif name in self.Context.Profiles:
  789.             self.Context.CurrentProfile = self.Context.Profiles[name]
  790.         else:
  791.             self.ProfileComboBox.set_active (0)
  792.             return
  793.  
  794.         self.ProfileRemoveButton.set_sensitive (self.ProfileComboBox.get_active() != 0)
  795.  
  796.         self.Context.Read()
  797.         self.Context.Write()
  798.         GlobalUpdater.UpdatePlugins()
  799.         return False
  800.  
  801.     def ProfileChangedAddTimeout(self, widget):
  802.         gobject.timeout_add (500, self.ProfileChanged, widget)
  803.  
  804.     def CreateFilter(self, chooser):
  805.         filter = gtk.FileFilter()
  806.         filter.add_pattern("*.profile")
  807.         filter.set_name(_("Profiles (*.profile)"))
  808.         chooser.add_filter(filter)
  809.  
  810.         filter = gtk.FileFilter()
  811.         filter.add_pattern("*")
  812.         filter.set_name(_("All files"))
  813.         chooser.add_filter(filter)
  814.  
  815.     def ResetProfile(self, widget):
  816.         
  817.         for plugin in self.Context.Plugins.values():
  818.             settings = GetSettings(plugin)
  819.             for setting in settings:
  820.                 setting.Reset()
  821.  
  822.         activePlugins = self.Context.Plugins['core'].Display['active_plugins'].Value
  823.         for plugin in self.Context.Plugins.values():
  824.             plugin.Enabled = plugin.Name in activePlugins
  825.         self.Context.Write()
  826.         GlobalUpdater.UpdatePlugins()
  827.     
  828.     def ExportProfile(self, widget):
  829.         main = widget.get_toplevel()
  830.         b = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)
  831.         chooser = gtk.FileChooserDialog(title=_("Save file.."), parent=main, buttons=b, action=gtk.FILE_CHOOSER_ACTION_SAVE)
  832.         chooser.set_current_folder(os.environ.get("HOME"))
  833.         self.CreateFilter(chooser)
  834.         ret = chooser.run()
  835.  
  836.         path = chooser.get_filename()
  837.         chooser.destroy()
  838.         if ret == gtk.RESPONSE_OK:
  839.             dlg = gtk.MessageDialog(type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO)
  840.             dlg.set_markup(_("Do you want to skip default option values while exporting your profile?"))
  841.             ret = dlg.run()
  842.             dlg.destroy()
  843.             self.Context.Export(path, ret == gtk.RESPONSE_YES)
  844.  
  845.     def ImportProfileDialog (self, main):
  846.         b = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
  847.              gtk.STOCK_OPEN, gtk.RESPONSE_OK)
  848.         chooser = gtk.FileChooserDialog (title = _("Open file.."),
  849.                                          parent = main, buttons = b)
  850.         chooser.set_current_folder (os.environ.get ("HOME"))
  851.         self.CreateFilter (chooser)
  852.         ret = chooser.run ()
  853.  
  854.         path = chooser.get_filename ()
  855.         chooser.destroy ()
  856.         if ret == gtk.RESPONSE_OK:
  857.             return path
  858.         return None
  859.  
  860.     def ProfileNameDialog (self, main):
  861.         dlg = gtk.Dialog (_("Enter a profile name"), main,
  862.                           gtk.DIALOG_MODAL)
  863.         dlg.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
  864.         dlg.add_button (gtk.STOCK_ADD, gtk.RESPONSE_OK)
  865.         
  866.         entry = gtk.Entry ()
  867.         label = gtk.Label (_("Please enter a name for the new profile:"))
  868.         dlg.vbox.pack_start (label, False, False, 5)
  869.         dlg.vbox.pack_start (entry, False, False, 5)
  870.  
  871.         dlg.set_size_request (340, 120)
  872.         dlg.show_all ()
  873.         ret = dlg.run ()
  874.         text = entry.get_text ()
  875.         dlg.destroy()
  876.         if ret == gtk.RESPONSE_OK:
  877.             return text
  878.         return None
  879.  
  880.     def ImportProfile (self, widget):
  881.         main = widget.get_toplevel ()
  882.         path = self.ImportProfileDialog (main)
  883.         if path:
  884.             self.Context.Import (path)
  885.         GlobalUpdater.UpdatePlugins()
  886.  
  887.     def ImportProfileAs (self, widget):
  888.         main = widget.get_toplevel ()
  889.         path = self.ImportProfileDialog (main)
  890.         if not path:
  891.             return
  892.         name = self.ProfileNameDialog ()
  893.         if not name:
  894.             return
  895.         self.Context.CurrentProfile = ccs.Profile (self.Context, name)
  896.         self.UpdateProfiles (name)
  897.         self.Context.Import (path)
  898.  
  899.     def AddProfile (self, widget):
  900.         main = widget.get_toplevel ()
  901.         name = self.ProfileNameDialog (main)
  902.         if name:
  903.             self.Context.CurrentProfile = ccs.Profile (self.Context, name)
  904.             self.UpdateProfiles (name)
  905.     
  906.     def RemoveProfile(self, widget):
  907.         name = self.ProfileComboBox.get_active_text()
  908.         if name != _("Default"):
  909.             self.Context.ResetProfile()
  910.             self.Context.Profiles[name].Delete()
  911.             self.UpdateProfiles()
  912.     
  913.     def BackendChanged(self, widget):
  914.         shortDesc = widget.get_active_text()
  915.         name = ""
  916.         for backend in self.Context.Backends.values():
  917.             if backend.ShortDesc == shortDesc:
  918.                 name = backend.Name
  919.                 break
  920.         
  921.         if name != "":
  922.             self.Context.ResetProfile()
  923.             self.Context.CurrentBackend = self.Context.Backends[name]
  924.             self.UpdateProfiles()
  925.         else:
  926.             raise Exception, _("Backend not found.")
  927.  
  928.         self.ProfileComboBox.set_sensitive(self.Context.CurrentBackend.ProfileSupport)
  929.         self.IntegrationButton.set_sensitive(self.Context.CurrentBackend.IntegrationSupport)
  930.         GlobalUpdater.UpdatePlugins()
  931.         return False
  932.  
  933.     def BackendChangedAddTimeout(self, widget):
  934.         gobject.timeout_add (500, self.BackendChanged, widget)
  935.  
  936. # Plugin List Page
  937. #
  938. class PluginListPage(object):
  939.     def __init__(self, context):
  940.         self.Context = context
  941.         self.Block = 0
  942.         rightChild = gtk.VBox()
  943.         rightChild.set_border_width(10)
  944.         
  945.         # Auto sort
  946.         autoSort = gtk.CheckButton(_("Automatic plugin sorting"))
  947.         rightChild.pack_start(autoSort, False, False, 10)
  948.         
  949.         # Lists
  950.         listBox = gtk.HBox()
  951.         listBox.set_spacing(5)
  952.  
  953.         self.DisabledPluginsList = ScrolledList(_("Disabled Plugins"))
  954.         self.EnabledPluginsList = ScrolledList(_("Enabled Plugins"))
  955.  
  956.         # Left/Right buttons
  957.         self.MiddleButtonBox = buttonBox = gtk.VBox()
  958.         buttonBox.set_spacing(5)
  959.         boxAlignment = gtk.Alignment(0.0, 0.5, 0.0, 0.0)
  960.         boxAlignment.add(buttonBox)
  961.  
  962.         rightButton = gtk.Button()
  963.         rightImage = Image(gtk.STOCK_GO_FORWARD, ImageStock, gtk.ICON_SIZE_BUTTON)
  964.         rightButton.set_image(rightImage)
  965.         rightButton.connect("clicked", self.EnablePlugins)
  966.  
  967.         leftButton = gtk.Button()
  968.         leftImage = Image(gtk.STOCK_GO_BACK, ImageStock, gtk.ICON_SIZE_BUTTON)
  969.         leftButton.set_image(leftImage)
  970.         leftButton.connect("clicked", self.EnabledPluginsList.delete)
  971.  
  972.         buttonBox.pack_start(rightButton, False, False)
  973.         buttonBox.pack_start(leftButton, False, False)
  974.  
  975.         # Up/Down buttons
  976.         enabledBox = gtk.VBox()
  977.         enabledBox.set_spacing(10)
  978.  
  979.         enabledAlignment = gtk.Alignment(0.5, 0.0, 0.0, 0.0)
  980.         self.EnabledButtonBox = enabledButtonBox = gtk.HBox()
  981.         enabledButtonBox.set_spacing(5)
  982.         enabledAlignment.add(enabledButtonBox)
  983.  
  984.         upButton = gtk.Button(gtk.STOCK_GO_UP)
  985.         downButton = gtk.Button(gtk.STOCK_GO_DOWN)
  986.         upButton.set_use_stock(True)
  987.         downButton.set_use_stock(True)
  988.         upButton.connect('clicked', self.EnabledPluginsList.move_up)
  989.         downButton.connect('clicked', self.EnabledPluginsList.move_down)
  990.  
  991.         # Add buttons
  992.         addButton = gtk.Button(gtk.STOCK_ADD)
  993.         addButton.set_use_stock(True)
  994.         addButton.connect('clicked', self.AddPlugin)
  995.  
  996.         enabledButtonBox.pack_start(addButton, False, False)
  997.         enabledButtonBox.pack_start(upButton, False, False)
  998.         enabledButtonBox.pack_start(downButton, False, False)
  999.  
  1000.         enabledBox.pack_start(self.EnabledPluginsList, True, True)
  1001.         enabledBox.pack_start(enabledAlignment, False, False)
  1002.  
  1003.         listBox.pack_start(self.DisabledPluginsList, True, True)
  1004.         listBox.pack_start(boxAlignment, True, False)
  1005.         listBox.pack_start(enabledBox, True, True)
  1006.  
  1007.         self.UpdateEnabledPluginsList()
  1008.         self.UpdateDisabledPluginsList()
  1009.  
  1010.         # Connect Store
  1011.         self.EnabledPluginsList.store.connect('row-changed', self.ListChanged)
  1012.         self.EnabledPluginsList.store.connect('row-deleted', self.ListChanged)
  1013.         self.EnabledPluginsList.store.connect('rows-reordered', self.ListChanged)
  1014.  
  1015.         rightChild.pack_start(listBox, True, True)
  1016.  
  1017.         # Auto sort
  1018.         autoSort.connect('toggled', self.AutoSortChanged)
  1019.         autoSort.set_active(self.Context.AutoSort)
  1020.  
  1021.         self.Widget = rightChild
  1022.  
  1023.     def AutoSortChanged(self, widget):
  1024.         if self.Block > 0:
  1025.             return
  1026.  
  1027.         autoSort = widget.get_active()
  1028.         if not autoSort:
  1029.             dlg = gtk.MessageDialog(type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_YES_NO)
  1030.             dlg.set_markup(_("Do you really want to disable automatic plugin sorting? This will also disable conflict handling. You should only do this if you know what you are doing."))
  1031.             response = dlg.run()
  1032.             dlg.destroy()
  1033.             if response == gtk.RESPONSE_NO:
  1034.                 self.Block += 1
  1035.                 widget.set_active(True)
  1036.                 self.Block -= 1
  1037.                 return
  1038.  
  1039.         self.Context.AutoSort = autoSort
  1040.  
  1041.         for widget in (self.EnabledPluginsList.view, self.DisabledPluginsList.view,
  1042.                 self.MiddleButtonBox, self.EnabledButtonBox):
  1043.             widget.set_sensitive(not self.Context.AutoSort)
  1044.  
  1045.         GlobalUpdater.UpdatePlugins()
  1046.  
  1047.     def UpdateEnabledPluginsList(self):
  1048.         activePlugins = self.Context.Plugins['core'].Display['active_plugins'].Value
  1049.         
  1050.         self.EnabledPluginsList.clear()
  1051.  
  1052.         for name in activePlugins:
  1053.             self.EnabledPluginsList.append(name)
  1054.  
  1055.     def UpdateDisabledPluginsList(self):
  1056.         activePlugins = self.Context.Plugins['core'].Display['active_plugins'].Value
  1057.  
  1058.         self.DisabledPluginsList.clear()
  1059.  
  1060.         for plugin in sorted(self.Context.Plugins.values(), key=PluginKeyFunc):
  1061.             if not plugin.Name in activePlugins and plugin.Name != "core":
  1062.                 self.DisabledPluginsList.append(plugin.Name)
  1063.  
  1064.     def AddPlugin(self, widget):
  1065.         dlg = gtk.Dialog(_("Add plugin"))
  1066.         dlg.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
  1067.         dlg.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK).grab_default()
  1068.         dlg.set_default_response(gtk.RESPONSE_OK)
  1069.         
  1070.         label = gtk.Label(_("Plugin name:"))
  1071.         label.set_tooltip_text(_("Insert plugin name"))
  1072.         dlg.vbox.pack_start(label)
  1073.         
  1074.         entry = gtk.Entry()
  1075.         entry.props.activates_default = True
  1076.         dlg.vbox.pack_start(entry)
  1077.  
  1078.         dlg.vbox.set_spacing(5)
  1079.         
  1080.         dlg.vbox.show_all()
  1081.         ret = dlg.run()
  1082.         dlg.destroy()
  1083.  
  1084.         if ret == gtk.RESPONSE_OK:
  1085.             self.EnabledPluginsList.append(entry.get_text())
  1086.  
  1087.     def EnablePlugins(self, widget):
  1088.         selectedRows = self.DisabledPluginsList.select.get_selected_rows()[1]
  1089.         for path in selectedRows:
  1090.             iter = self.DisabledPluginsList.store.get_iter(path)
  1091.             name = self.DisabledPluginsList.store.get(iter, 0)[0]
  1092.             self.EnabledPluginsList.append(name)
  1093.         self.DisabledPluginsList.delete(widget)
  1094.     
  1095.     def ListChanged(self, *args, **kwargs):
  1096.         if self.Block > 0:
  1097.             return
  1098.         self.Block += 1
  1099.         plugins = self.EnabledPluginsList.get_list()
  1100.  
  1101.         self.Context.Plugins['core'].Display['active_plugins'].Value = plugins
  1102.         self.Context.Write()
  1103.         self.UpdateDisabledPluginsList()
  1104.         self.Block -= 1
  1105.  
  1106. # Preferences Page
  1107. #
  1108. class PreferencesPage(GenericPage):
  1109.     def __init__(self, context):
  1110.         GenericPage.__init__(self)
  1111.         self.Context = context
  1112.         self.LeftWidget = gtk.VBox(False, 10)
  1113.         self.LeftWidget.set_border_width(10)
  1114.         self.RightWidget = gtk.Notebook()
  1115.  
  1116.         # Left Pane
  1117.         self.DescLabel = Label()
  1118.         self.DescLabel.set_markup(HeaderMarkup % (_("Preferences")))
  1119.         self.DescLabel.connect("style-set", self.HeaderStyleSet)
  1120.         self.DescImg = Image("profiles",ImageCategory, 64)
  1121.         self.LeftWidget.pack_start(self.DescImg, False, False)
  1122.         self.LeftWidget.pack_start(self.DescLabel, False, False)
  1123.         self.InfoLabelCont = gtk.HBox()
  1124.         self.InfoLabelCont.set_border_width(10)
  1125.         self.LeftWidget.pack_start(self.InfoLabelCont, False, False)
  1126.         self.InfoLabel = Label(_("Configure the backend, profile and other internal settings used by the Compiz Configuration System."), 180)
  1127.         self.InfoLabelCont.pack_start(self.InfoLabel, True, True)
  1128.  
  1129.         # About Button
  1130.         aboutLabel = Label()
  1131.         aboutLabel.set_markup(HeaderMarkup % (_("About")))
  1132.         aboutLabel.connect("style-set", self.HeaderStyleSet)
  1133.         aboutButton = gtk.Button()
  1134.         aboutButton.set_relief(gtk.RELIEF_NONE)
  1135.         aboutImage = Image(gtk.STOCK_ABOUT, ImageStock, gtk.ICON_SIZE_BUTTON)
  1136.         aboutFrame = gtk.HBox()
  1137.         aboutFrame.set_spacing(5)
  1138.         aboutFrame.pack_start(aboutImage, False, False)
  1139.         aboutFrame.pack_start(Label(_("About CCSM...")), False, False)
  1140.         aboutButton.add(aboutFrame)
  1141.         aboutButton.set_tooltip_text(_("About"))
  1142.         aboutButton.connect('clicked', self.ShowAboutDialog)
  1143.         aboutBin = gtk.HBox()
  1144.         aboutBin.set_border_width(10)
  1145.         aboutBin.pack_start(aboutButton, False, False)
  1146.         self.LeftWidget.pack_start(aboutLabel, False, False)
  1147.         self.LeftWidget.pack_start(aboutBin, False, False)
  1148.     
  1149.         # Back Button
  1150.         backButton = gtk.Button(gtk.STOCK_GO_BACK)
  1151.         backButton.set_use_stock(True)
  1152.         backButton.connect('clicked', self.GoBack)
  1153.         self.LeftWidget.pack_end(backButton, False, False)
  1154.  
  1155.         # Profile & Backend Page
  1156.         self.ProfileBackendPage = ProfileBackendPage(context)
  1157.         self.RightWidget.append_page(self.ProfileBackendPage.Widget, gtk.Label(_("Profile & Backend")))
  1158.  
  1159.         # Plugin List
  1160.         self.PluginListPage = PluginListPage(context)
  1161.         self.RightWidget.append_page(self.PluginListPage.Widget, gtk.Label(_("Plugin List")))
  1162.  
  1163.     StyleBlock = 0
  1164.  
  1165.     def HeaderStyleSet(self, widget, previous):
  1166.         if self.StyleBlock > 0:
  1167.             return
  1168.         self.StyleBlock += 1
  1169.         for state in (gtk.STATE_NORMAL, gtk.STATE_PRELIGHT, gtk.STATE_ACTIVE):
  1170.             widget.modify_fg(state, widget.style.bg[gtk.STATE_SELECTED])
  1171.         self.StyleBlock -= 1
  1172.  
  1173.     def ShowAboutDialog(self, widget):
  1174.         about = AboutDialog(widget.get_toplevel())
  1175.         about.show_all()
  1176.         about.run()
  1177.         about.destroy()
  1178.  
  1179. # Main Page
  1180. #
  1181. class MainPage(object):
  1182.     def __init__(self, main, context):
  1183.         self.Context = context
  1184.         self.Main    = main
  1185.         sidebar = gtk.VBox(False, 10)
  1186.         sidebar.set_border_width(10)
  1187.         pluginWindow = PluginWindow(self.Context)
  1188.         pluginWindow.connect('show-plugin', self.ShowPlugin)
  1189.  
  1190.         # Filter
  1191.         filterLabel = Label()
  1192.         filterLabel.set_markup(HeaderMarkup % (_("Filter")))
  1193.         filterLabel.connect("style-set", self.HeaderStyleSet)
  1194.         filterLabel.props.xalign = 0.1
  1195.         if has_sexy:
  1196.             filterEntry = sexy.IconEntry()
  1197.             filterEntry.add_clear_button()
  1198.         else:
  1199.             filterEntry = gtk.Entry()
  1200.         filterEntry.set_tooltip_text(_("Filter your Plugin list"))
  1201.         filterEntry.connect("changed", self.FilterChanged)
  1202.         self.filterEntry = filterEntry
  1203.  
  1204.         # Screens
  1205.         if len(getScreens()) > 1:
  1206.             screenBox = gtk.combo_box_new_text()
  1207.             for screen in getScreens():
  1208.                 screenBox.append_text(_("Screen %i") % screen)
  1209.             name = self.Context.CurrentBackend.Name
  1210.             screenBox.set_active(CurrentScreenNum)
  1211.             screenBox.connect("changed", self.ScreenChanged)
  1212.             screenLabel = Label()
  1213.             screenLabel.set_markup(HeaderMarkup % (_("Screen")))
  1214.             screenLabel.connect("style-set", self.HeaderStyleSet)
  1215.  
  1216.             sidebar.pack_start(screenLabel, False, False)
  1217.             sidebar.pack_start(screenBox, False, False)
  1218.  
  1219.         # Categories
  1220.         categoryBox = gtk.VBox()
  1221.         categoryBox.set_border_width(5)
  1222.         categories = ['All'] + sorted(pluginWindow.get_categories(), key=CategoryKeyFunc)
  1223.         for category in categories:
  1224.             # name: untranslated name/interal identifier
  1225.             # label: translated name
  1226.             name = category or 'Uncategorized'
  1227.             label = _(name)
  1228.             iconName = name.lower ().replace (" ", "_")
  1229.             categoryToggleIcon = Image (name = iconName, type = ImageCategory,
  1230.                                         size = 22)
  1231.             categoryToggleLabel = Label (label)
  1232.             align = gtk.Alignment (0, 0.5, 1, 1)
  1233.             align.set_padding (0, 0, 0, 10)
  1234.             align.add (categoryToggleIcon)
  1235.             categoryToggleBox = gtk.HBox ()
  1236.             categoryToggleBox.pack_start (align, False, False)
  1237.             categoryToggleBox.pack_start (categoryToggleLabel, True, True)
  1238.             categoryToggle = PrettyButton ()
  1239.             categoryToggle.add(categoryToggleBox)
  1240.             categoryToggle.connect("clicked", self.ToggleCategory, category)
  1241.             categoryBox.pack_start(categoryToggle, False, False)
  1242.         categoryLabel = Label()
  1243.         categoryLabel.props.xalign = 0.1
  1244.         categoryLabel.set_markup(HeaderMarkup % (_("Category")))
  1245.         categoryLabel.connect("style-set", self.HeaderStyleSet)
  1246.  
  1247.         # Exit Button
  1248.         exitButton = gtk.Button(gtk.STOCK_CLOSE)
  1249.         exitButton.set_use_stock(True)
  1250.         exitButton.connect('clicked', self.Main.Quit)
  1251.  
  1252.         # Advanced Search
  1253.         searchLabel = Label()
  1254.         searchLabel.set_markup(HeaderMarkup % (_("Advanced Search")))
  1255.         searchLabel.connect("style-set", self.HeaderStyleSet)
  1256.         searchImage = gtk.Image()
  1257.         searchImage.set_from_stock(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
  1258.         searchButton = PrettyButton()
  1259.         searchButton.connect("clicked", self.ShowAdvancedFilter)
  1260.         searchButton.set_relief(gtk.RELIEF_NONE)
  1261.         searchFrame = gtk.HBox()
  1262.         searchFrame.pack_start(searchLabel, False, False)
  1263.         searchFrame.pack_end(searchImage, False, False)
  1264.         searchButton.add(searchFrame)
  1265.  
  1266.         # Preferences
  1267.         prefLabel = Label()
  1268.         prefLabel.set_markup(HeaderMarkup % (_("Preferences")))
  1269.         prefLabel.connect("style-set", self.HeaderStyleSet)
  1270.         prefImage = gtk.Image()
  1271.         prefImage.set_from_stock(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
  1272.         prefButton = PrettyButton()
  1273.         prefButton.connect("clicked", self.ShowPreferences)
  1274.         prefButton.set_relief(gtk.RELIEF_NONE)
  1275.         prefFrame = gtk.HBox()
  1276.         prefFrame.pack_start(prefLabel, False, False)
  1277.         prefFrame.pack_end(prefImage, False, False)
  1278.         prefButton.add(prefFrame)
  1279.  
  1280.         # Pack widgets into sidebar
  1281.         sidebar.pack_start(filterLabel, False, False)
  1282.         sidebar.pack_start(filterEntry, False, False)
  1283.         sidebar.pack_start(categoryLabel, False, False)
  1284.         sidebar.pack_start(categoryBox, False, False)
  1285.         sidebar.pack_end(exitButton, False, False)
  1286.         sidebar.pack_end(searchButton, False, False)
  1287.         sidebar.pack_end(prefButton, False, False)
  1288.  
  1289.         self.LeftWidget = sidebar
  1290.         self.RightWidget = pluginWindow
  1291.  
  1292.     StyleBlock = 0
  1293.  
  1294.     def HeaderStyleSet(self, widget, previous):
  1295.         if self.StyleBlock > 0:
  1296.             return
  1297.         self.StyleBlock += 1
  1298.         for state in (gtk.STATE_NORMAL, gtk.STATE_PRELIGHT, gtk.STATE_ACTIVE):
  1299.             widget.modify_fg(state, widget.style.bg[gtk.STATE_SELECTED])
  1300.         self.StyleBlock -= 1
  1301.  
  1302.     def ShowPlugin(self, widget, plugin):
  1303.         pluginPage = PluginPage(plugin)
  1304.         self.Main.SetPage(pluginPage)
  1305.  
  1306.     def ShowAdvancedFilter(self, widget):
  1307.         filterPage = FilterPage(self.Context)
  1308.         self.Main.SetPage(filterPage)
  1309.  
  1310.     def ShowPreferences(self, widget):
  1311.         preferencesPage = PreferencesPage(self.Context)
  1312.         self.Main.SetPage(preferencesPage)
  1313.  
  1314.     def ToggleCategory(self, widget, category):
  1315.         if category == 'All':
  1316.             category = None
  1317.         else:
  1318.             category = category.lower()
  1319.         self.RightWidget.filter_boxes(category, level=FilterCategory)
  1320.  
  1321.     def FilterChanged(self, widget):
  1322.         text = widget.get_text().lower()
  1323.         self.RightWidget.filter_boxes(text)
  1324.  
  1325.     def ScreenChanged(self, widget):
  1326.         self.Context.Write()
  1327.         self.CurrentScreenNum = widget.get_active()
  1328.         self.Context.Read()
  1329.  
  1330. # Page
  1331. #
  1332. class Page(object):
  1333.     def __init__(self):
  1334.         self.SetContainer = gtk.VBox()
  1335.  
  1336.         self.Widget = gtk.EventBox()
  1337.         self.Widget.add(self.SetContainer)
  1338.  
  1339.         self.Empty = True
  1340.  
  1341.     def Wrap(self):
  1342.         scroll = gtk.ScrolledWindow()
  1343.         scroll.props.hscrollbar_policy = gtk.POLICY_NEVER
  1344.         scroll.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
  1345.  
  1346.         view = gtk.Viewport()
  1347.         view.set_border_width(5)
  1348.         view.set_shadow_type(gtk.SHADOW_NONE)
  1349.  
  1350.         scroll.add(view)
  1351.         view.add(self.Widget)
  1352.  
  1353.         self.Scroll = scroll
  1354.  
  1355.  
  1356. # Group Page
  1357. #
  1358. class GroupPage(Page):
  1359.     def __init__(self, name, group):
  1360.         Page.__init__(self)
  1361.  
  1362.         self.Name = name
  1363.         self.VisibleAreas = self.subGroupAreas = []
  1364.         self.Label = gtk.Alignment(xalign=0.0, yalign=0.5)
  1365.         self.Label.set_padding(4, 4, 4, 4)
  1366.         label = gtk.Label("<b>%s</b>" %(protect_pango_markup(name or _('General'))))
  1367.         label.set_use_markup(True)
  1368.         self.Label.add(label)
  1369.         if '' in group:
  1370.             sga = SubGroupArea('', group[''][1])
  1371.             if not sga.Empty:
  1372.                 self.SetContainer.pack_start(sga.Widget, False, False)
  1373.                 self.Empty = False
  1374.                 self.subGroupAreas.append(sga)
  1375.  
  1376.         sortedSubGroups = sorted(group.items(), key=GroupIndexKeyFunc)
  1377.         for (subGroupName, (subGroupIndex, subGroup)) in sortedSubGroups:
  1378.             if not subGroupName == '':
  1379.                 sga = SubGroupArea(subGroupName, subGroup)
  1380.                 if not sga.Empty:
  1381.                     self.SetContainer.pack_start(sga.Widget, False, False)
  1382.                     self.Empty = False
  1383.                     self.subGroupAreas.append(sga)
  1384.  
  1385.         self.Visible = not self.Empty
  1386.  
  1387.     def Filter(self, text, level=FilterAll):
  1388.         empty = True
  1389.         self.VisibleAreas = []
  1390.         for area in self.subGroupAreas:
  1391.             if area.Filter(text, level=level):
  1392.                 self.VisibleAreas.append(area)
  1393.                 empty = False
  1394.  
  1395.         self.Visible = not empty
  1396.  
  1397.         self.Label.props.no_show_all = empty
  1398.         if empty:
  1399.             self.Label.hide()
  1400.         else:
  1401.             self.Label.show()
  1402.  
  1403.         return not empty
  1404.  
  1405.  
  1406.